﻿
using System;
using IScheduler.Core.Business;
using IScheduler.Core.Properties;
using System.Collections.Generic;

namespace IScheduler.Core.Schedule.Monitor
{
    public enum StatusType
    {
        None, //default 
        Online,
        Offline
    }

    public enum StatusEventType
    {
        None, //default
        Starting,
        Started,
        Stopped,
        Stopping,
        Sleeping,
        Error,
        Warn,
        Working
    }


    public delegate void DelegateScheduleMonitorEventStatusHandler(object sender, EventArgs e);
    public delegate void DelegateScheduleMonitorStatusHandler(object sender, EventArgs e);

    public class ScheduleMonitor
    {
        //Events
        private event DelegateScheduleMonitorEventStatusHandler StatusEventChanged;
        private event DelegateScheduleMonitorStatusHandler StatusChanged;

        private System.Timers.Timer timerMonitor;
        private StatusEventType statusEvent;
        private StatusType status;
        private string SessionId { get; set; }
        
        private IList<ScheduleTimer> Schedules;
        

        /// <summary>
        /// Get/Set ScheduleMonitor's Event Status
        /// </summary>
        public StatusEventType StatusEvent 
        { 
            get
            { return this.statusEvent; } 
            set
            { 
              this.statusEvent = value;
              StatusEventChanged(this, EventArgs.Empty); 
            } 
        }

        /// <summary>
        /// Get/Set ScheduleMonitor's Status
        /// </summary>
        public StatusType Status
        {
            get
            { return this.status; }
            set
            {
                this.status = value;
                StatusChanged(this, EventArgs.Empty);
            }
        }
        

        /// <summary>
        /// Constructor
        /// </summary>
        public ScheduleMonitor()
        {
            //setup event status change event
            StatusEventChanged += new DelegateScheduleMonitorEventStatusHandler(ScheduleMonitor_OnStatusEventChanged);

            //setup event status change event
            StatusChanged += new DelegateScheduleMonitorStatusHandler(ScheduleMonitor_OnStatusChanged);
        }

        /// <summary>
        /// Dispatch Event Status Changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScheduleMonitor_OnStatusChanged(object sender, EventArgs e)
        {
            LoggingService.InfoFormatted(Resources.ScheduleMonitorStatusInfo, Status.ToString());
        }

        /// <summary>
        /// Dispatch Event Status Changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScheduleMonitor_OnStatusEventChanged(object sender, EventArgs e)
        {
            LoggingService.InfoFormatted(Resources.ScheduleMonitorStatusInfo, StatusEvent.ToString());
        }

        /// <summary>
        /// Check if there is any database connection.
        /// It will only change the status if the has been changed only to avoid many
        /// call of StatusEventChanged.
        /// </summary>
        public bool HasDatabaseConnection
        {
            get
            {
            	ScheduleMonitorBusiness business = new ScheduleMonitorBusiness();
            	
            	//checking if the database is up and running.
            	if (business.IsDatabaseUpAndRunning())
            	{
                    if (Status != StatusType.Online)
                    {
                        Status = StatusType.Online;
                    }            		
            	}
            	else
            	{
                    if (Status != StatusType.Offline)
                    {
                        Status = StatusType.Offline;
                    }            		
            	}
            	
                return true;
            }
        }

        /// <summary>
        /// Start Scheduler Monitor Services
        /// </summary>
        public void StartService()
        {
            try
            {
                //start new session
                SessionId = GetNewSession();

                //set initial status
                StatusEvent = StatusEventType.Starting;

                //start timer elapse
                timerMonitor = new System.Timers.Timer(SettingService.Settings.MonitorTimerElapsed);
                timerMonitor.Elapsed += new System.Timers.ElapsedEventHandler(OnEventTimerMonitor_Elapsed);
                timerMonitor.Enabled = true;

                StatusEvent = StatusEventType.Started;
            }
            catch
            {
                StatusEvent = StatusEventType.Error;
            }
        }

        /// <summary>
        /// Stop Scheduler Monitor Services
        /// </summary>
        public void StopService()
        {
            try
            {
                StatusEvent = StatusEventType.Stopping;

                timerMonitor.Stop();
                
                StatusEvent = StatusEventType.Stopped;
                Status = StatusType.None;
            }
            catch
            {
                StatusEvent = StatusEventType.Error;
            }
        }



        /// <summary>
        /// Scheduler Event Timer Elapsed (do not change)
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void OnEventTimerMonitor_Elapsed(object source, System.Timers.ElapsedEventArgs e)
        {
            StatusEvent = StatusEventType.Working;
            
            Run();
            
            StatusEvent = StatusEventType.Sleeping;
        }

        /// <summary>
        /// Every elapsed this function is called.
        /// </summary>
        private void Run()
        {
            try
            {
                //check database connection
                if (HasDatabaseConnection)
                {
                	CheckSchedules();
                }
            }
            catch
            {
                throw;
            }
        }
        
        /// <summary>
        /// Check if is there any scheduler to be started.
        /// </summary>
        private void CheckSchedules()
        {
        	ScheduleMonitorBusiness business = new ScheduleMonitorBusiness();
        	business.BuildSchedules(ref Schedules);
        }
        

        /// <summary>
        /// Get a new generated session and setup it at logger.
        /// </summary>
        /// <returns></returns>
        private string GetNewSession()
        {
            string session = UtilService.GenerateSessionGuid();

            //setup the new session id
            log4net.GlobalContext.Properties["guid_session"] = session;

            //logging new session id for debug
            LoggingService.InfoFormatted(Resources.ScheduleMonitorSessionIdSuccessful, session);
            
            return session;
        }

    }
}
